<template>
    <div class="hello">
        <h3>概要</h3>
        <h3>ts函数声明, 函数可选参数，参数类型定义,指定参数(指定值)，输出指定值，函数重载与函数签名</h3>
        <hr>
        <h3> undefined ,null  ?.与!. 运算符</h3>
        <h3> typeof 与 instanceof</h3>
        <h3> ts的 this作为参数 (不知道什么用)</h3>
    </div>
</template>

<script setup lang="ts">

    type sn = string | number
    // 基本的函数
    function func1(str:sn):sn{
        console.log("str",str)
        return str
    }
    func1("typescript")
    // 无返回值
    function func2(str:string):void {
        console.log("无返回值")
    }

    /* 函数声明的完整写法  base 与add1 可以名称不一样*/
    const add:(base:number,increment:number)=>number = function (add1:number,add2:number):number {
        return add1+add2;
    }


    // 定义联合的 文字类型(string number boolean) 用于 传输 指定值
    type characterType = 'left' | 'right' | 'center'
    type methodType = 'get' | 'post' | 'put'
    type numberType = 1 | 2 | 3
    type booleanType = true | false

    function printText(s: string, alignmentssss: characterType) { // 第二个参数只能是三个之一
        console.log(alignmentssss)
    }
    const dir = {
        a:"left" as characterType // 因为dir.a 是变量的形式 不一定是 characterType类型 需要指定类型
    }
    printText('hello',dir.a) //


    // 函数返回值只能是 -1 | 0 | 1
    // b 要么是string 要么 是指定值
    function compare(a: string, b: string | 20 | booleanType): -1 | 0 | 1 {
        const res = a === b ? 0 : a > b ? 1 : -1
        console.log("res",res)
        return res
    }
    compare("1",false)

    /* ! 直接排除null 和undefined,   ?. 是有没有值再去调相应的方法*/
    function liveDangerously(x?: number | null | undefined, y?:number[]) { // x? 参数可填可不填
        // console.log(x.toFixed())  // x可能是null 或者是 undefined 要解决这种报错使用!.运算符
        console.log("x",x!.toFixed(1)); //toFixed 不改变原值
        // 或者自己写js判断
        console.log("y",y?.length)
    }
    liveDangerously(2.15,[1,2,3])


    // typeof和 instanceof 去缩小类型 再做 相应的操作
    // 问题引出 typeof strs === 'object' 使用instanceof
    function printAll(strs: string | string[] | null) {
        //&& strs 如果是 null 直接就就进不去
        if (strs && strs instanceof Object) {
            console.log("strs",strs)
            for (const s of strs) {
                console.log(s)
            }
        } else if (typeof strs === 'string') {
            console.log("string",strs)
        } else {
            // ...
            console.log("hello")
        }
    }
    printAll("hello world")
    printAll(["1","2","3"])
    printAll(null)

    //undefined 与 null 的相等判断
    function test(container: number | null | undefined , factor: number) {
        if (container != null) { // != 这种判断会直接 过滤undefined null  == 判断
            console.log(container)
            container *= factor
        }
        if (container == null){  // undefined 和null 都会进来
            console.log(container)
        }
    }
    test(undefined,20)
    test(null,20)

    // 函数少些可选参数 尽量使用默认参数
    // 回调函数最好不要写可选参数
    function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
        for (let i = 0; i < arr.length; i++) {
            callback(arr[i],i)
            // callback(arr[i],i)
        }
    }
    // myForEach([1, 2, 3], (a) => console.log(a))
    // myForEach([1, 3, 4], (a, i) => console.log(a, i))
    // myForEach([1, 2, 3], (a, i) => {console.log(i!.toFixed())})

    // 函数重载 （一般不用，因为参数可以联合类型）
    // 函数声明 之后一定要去实现 否则报错
    function fnnn(x: string): string
    function fnnn(x: boolean): boolean
    // 实现的时候需要兼容前面的string boolean 包括返回值类型
    function fnnn(x: string | boolean): string | boolean {return 'hello'}

    function fnn(x: string): void
    function fnn() {} // 实现签名
    fnn('hello')  // 传参以声明的函数为主 不写传参就报错

    //ts的 this作为参数 (不知道什么用)
    // interface User {
    //     admin: boolean
    // }
    // 本质是函数式接口
    // interface DB {
    //     (filter: (this: User) => boolean): User[]  // 参数名this  类型是Uer  返回值是布尔  最终返回 User[]
    // }
    // const filterUsers:DB = (filter:(this:User) => boolean)=> {
    //     let user1: User = {admin: true}
    //     let user2: User = {admin: false}
    //     return [user1, user2]
    // }
    // const admins = filterUsers(function (this:User) {
    //     return this.admin
    // })
    // console.log(admins);

    // ...参数
    // function multiplys(n: number, ...m: number[]) {  // m = [1, 2, 3, 4, 60, 100]
    //     return m.map( x => n * x )
    // }
    // const aaa = multiplys(10, 1, 2, 3, 4, 60, 100)
    // console.log(aaa)

    // ...参数 参数解构
    type ABC = { a: number, b: number, c: number }
    function sum({ a:s, b, c }: ABC) {
        console.log(s + b + c)
        return { s, b, c }
    }
    console.log(sum({a: 10, b: 20, c: 0}))

    // 返回值类型是void但是 接收的时候不能声明成其他类型
    type voidFunc = () => void
    const f1:voidFunc = () => true
    const f2:() => void = () => 100
    const f3:() => void = ()=> "hello"
    const v1:void = f1();console.log(v1)
    const v2 = f2(); console.log(v2)
    const v3 = f3(); console.log(v3)
    // function f4(): void {return true}  // 这两种声明式 返回值类型是void 就不能return返回值
    // const f5 = function(): void {return true}



    interface NumberBox {
        contents: number
    }
    interface StringBox {
        contents: string
    }
    interface BooleanBox {
        contents: boolean
    }
    // 函数重载声明
    function setContents(box: StringBox, newContents: string): void
    function setContents(box: NumberBox, newContents: number): void
    function setContents(box: BooleanBox, newContents: boolean): void
    function setContents(box: { contents: any }, newContents: any) {
        box.contents = newContents
    }

    //几个通用的泛型
    type Box<T> = {
        contents: T
    }
    type OrNull<T> = T | null // 任意类型或 NULL
    // let t1:OrNull<string> = "123"
    // t1 = null
    type OneOrMany<T> = T | T[] // 任意类型或者 任意类型数组
    let t2:OneOrMany<string> = ["1","1","1"]
    t2 = []

    type OneOrManyOrNull<T> = OrNull<OneOrMany<T>> // 任意类型或者 任意类型数组 或者NULL
    let t3:OneOrManyOrNull<number> = [10,20]
    t3 = null
    t3 =[]

    type OneOrManyOrNullString = OneOrManyOrNull<string>  // 确定类型
    let t4:OneOrManyOrNullString = "123"

    function testFanxi<T>(a:T,b:T):T[] {
        return [a,b]
    }
</script>

<style scoped>

</style>
